﻿#include <comdef.h>
#include "Python.h"
#include "IOEngine.h"
#include "SharedMemory.h"

static PyObject* _init_drv(PyObject* self, PyObject* args)
{
	ulong pid = 0;
	bool result = 0;
	if (PyArg_ParseTuple(args, "k", &pid))
	{
		result = init_drv();
		if (result)
		{
			string name = "trex_shared_memory_" + to_string(pid);
			_bstr_t bstr(name.c_str());
			lpMapName = (LPTSTR)bstr;
		}
	}
	return PyLong_FromLong(result);
}

static PyObject* _deinit_drv(PyObject* self, PyObject* args)
{
	bool result = 0;
	if (PyArg_ParseTuple(args, ""))
	{
		result = deinit_drv();
	}
	return PyLong_FromLong(result);
}

static PyObject* _set_reg_addr(PyObject* self, PyObject* args)
{
	ushort base, alt;
	byte dev;
	if (PyArg_ParseTuple(args, "HHB", &base, &alt, &dev))
	{
		set_reg_addr(base, alt, dev);
	}
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* _inp(PyObject* self, PyObject* args)
{
	ushort port;
	byte result = 0;
	if (PyArg_ParseTuple(args, "H", &port))
	{
		result = inp(port);
	}
	return Py_BuildValue("B", result);
}

static PyObject* _inpw(PyObject* self, PyObject* args)
{
	ushort port, result = 0;
	if (PyArg_ParseTuple(args, "H", &port))
	{
		result = inpw(port);
	}
	return Py_BuildValue("H", result);
}

static PyObject* _inpd(PyObject* self, PyObject* args)
{
	ushort port;
	ulong result = 0;
	if (PyArg_ParseTuple(args, "H", &port))
	{
		result = inpd(port);
	}
	return Py_BuildValue("k", result);
}

static PyObject* _outp(PyObject* self, PyObject* args)
{
	ushort port;
	byte value;
	if (PyArg_ParseTuple(args, "HB", &port, &value))
	{
		outp(port, value);
	}
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* _outpw(PyObject* self, PyObject* args)
{
	ushort port, value;
	if (PyArg_ParseTuple(args, "HH", &port, &value))
	{
		outpw(port, value);
	}
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* _outpd(PyObject* self, PyObject* args)
{
	ushort port;
	ulong value;
	if (PyArg_ParseTuple(args, "Hk", &port, &value))
	{
		outpd(port, value);
	}
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* _read_pci_config_byte(PyObject* self, PyObject* args)
{
	ulong pciAddress;
	byte regAddress;
	byte result = 0;
	if (PyArg_ParseTuple(args, "kB", &pciAddress, &regAddress))
	{
		result = ReadPciConfigByte(pciAddress, regAddress);
	}
	return Py_BuildValue("B", result);
}

static PyObject* _read_pci_config_word(PyObject* self, PyObject* args)
{
	ulong pciAddress;
	byte regAddress;
	ushort result = 0;
	if (PyArg_ParseTuple(args, "kB", &pciAddress, &regAddress))
	{
		result = ReadPciConfigWord(pciAddress, regAddress);
	}
	return Py_BuildValue("H", result);
}

static PyObject* _read_pci_config_dword(PyObject* self, PyObject* args)
{
	ulong pciAddress;
	byte regAddress;
	ulong result = 0;
	if (PyArg_ParseTuple(args, "kB", &pciAddress, &regAddress))
	{
		result = ReadPciConfigDword(pciAddress, regAddress);
	}
	return Py_BuildValue("k", result);
}

static PyObject* _read_data(PyObject* self, PyObject* args)
{
	ulong offset = 0;
	ushort count = 0;
	ulong timeout = 10;
	bool result = 0;
	if (PyArg_ParseTuple(args, "kH|k", &offset, &count, &timeout))
	{
		byte* buffer = (byte*)calloc(count * 512, sizeof(byte));
		if (read_data(buffer, timeout))
		{
			result = WriteSharedMemory(buffer, offset);
		}
		free(buffer);
	}
	return PyBool_FromLong(result);
}

static PyObject* _write_data(PyObject* self, PyObject* args)
{
	ulong offset = 0;
	ushort count = 0;
	ulong timeout = 10;
	bool result = 0;
	if (PyArg_ParseTuple(args, "kH|k", &offset, &count, &timeout))
	{
		byte* buffer = (byte*)calloc(count * 512, sizeof(byte));
		if (ReadSharedMemory(buffer, offset))
		{
			result = write_data(buffer, timeout);
		}
		free(buffer);
	}
	return PyBool_FromLong(result);
}

static PyMethodDef IOEngineMethods[] = {
	{ "init_drv", _init_drv, METH_VARARGS, "drv_init(pid) -> bool" },
	{ "deinit_drv", _deinit_drv, METH_VARARGS, "drv_deinit() -> bool" },
	{ "set_reg_addr", _set_reg_addr, METH_VARARGS, "set_reg_addr(base, alt, dev) -> None" },
	{ "inp", _inp, METH_VARARGS, "inp(port) -> int" },
	{ "inpw", _inpw, METH_VARARGS, "inpw(port) -> int" },
	{ "inpd", _inpd, METH_VARARGS, "inpd(port) -> int" },
	{ "outp", _outp, METH_VARARGS, "outp(port, value) -> None" },
	{ "outpw", _outpw, METH_VARARGS, "outpw(port, value) -> None" },
	{ "outpd", _outpd, METH_VARARGS, "outpd(port, value) -> None" },
	{ "read_pci_config_byte", _read_pci_config_byte, METH_VARARGS, "read_pci_config_byte(pci_address, reg_address) -> int" },
	{ "read_pci_config_word", _read_pci_config_word, METH_VARARGS, "read_pci_config_word(pci_address, reg_address) -> int" },
	{ "read_pci_config_dword", _read_pci_config_dword, METH_VARARGS, "read_pci_config_dword(pci_address, reg_address) -> int" },
	{ "read_data", _read_data, METH_VARARGS, "read_data(buffer, count, timeout) -> bool"},
	{ "write_data", _write_data, METH_VARARGS, "write_data(buffer, count, timeout) -> bool"},
	{ NULL, NULL, 0, NULL }
};

static struct PyModuleDef IOEngineModule = {
	PyModuleDef_HEAD_INIT,
	"IOEngine",
	"...",
	-1,
	IOEngineMethods
};

PyMODINIT_FUNC PyInit_IOEngine(void)
{
	PyObject* module = PyModule_Create(&IOEngineModule);
	return module;
}
